package com.sduept.nwld.dataserver.manager.faultforecast;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 朴素贝叶斯分类+正态分布/高斯分布实现数据分类
 */
@Slf4j
public class NaiveBayes {

	/**
	 * 根据已有样本，利用朴素贝叶斯分类器算法预测所传入数据是否是故障
	 * p=p(x1/类别)*p(x2/类别)*p(x3/类别)*p(x.../类别)*p(类别)
	 * @param sampleMap 样本（key：类型，value：数据集）
	 * @param dataSize 总数据个数
	 * @param dataArr 要预测数据，值的顺序和sampleMap的value数据集保持一致（如：样本数据是[长度，宽度，高度]，则要预测数据顺序也是[长度，宽度，高度]）
	 * @return 要预测数据属于各类别的概率（key：类型，value：概率）
	 */
	public static Map<String, Double> faultForcast(Map<String, List<double[]>> sampleMap, int dataSize, double[] dataArr){
		
		Map<String, Double> resultMap = new HashMap<String, Double>();//要预测数据属于各类别的概率（key：类型，value：概率）
		if(sampleMap.size() > 0 && dataSize > 0 && dataArr.length > 0){
			
			for(Map.Entry<String, List<double[]>> entry : sampleMap.entrySet()){
				
				double[] averageArr = average(entry.getValue());//平均值
				double[] deviationArr = deviation(entry.getValue(), averageArr);//标准差
				double naiveBayes = (double)entry.getValue().size()/(double)dataSize;//初始值为p（类概率）
				for(int i = 0; i < averageArr.length; i++){
					
					naiveBayes = naiveBayes * gaussianDistribution(dataArr[i], averageArr[i], deviationArr[i]);
				}
				
				resultMap.put(entry.getKey(), naiveBayes);
			}
		}
		return resultMap;
	}
	
	/**
	 * 计算平均值
	 * @param dataList 数据
	 * @return 平均值数组，顺序和所传入数据的顺序一致
	 */
	public static double[] average(List<double[]> dataList){
		
		int size = dataList.size();//数据条数
		int arrSize = dataList.get(0).length;//数组大小
		double[] sumArr = new double[arrSize];//存储数据和，顺序和传入数据一致
		for(double[] data : dataList){
			
			for(int i = 0; i < data.length; i++){
				sumArr[i] += data[i];
			}
		}
		double[] averageArr = new double[arrSize];//各平均值，顺序和传入数据一致
		for(int i = 0; i < arrSize; i++){
			
			averageArr[i] = sumArr[i]/size;
		}
		
		return averageArr;
	}
	
	/**
	 * 计算标准差
	 * @param dataList 数据
	 * @param averageArr 平均值
	 * @return 标准差数组，顺序和所传入数据的顺序一致
	 */
	public static double[] deviation(List<double[]> dataList, double[] averageArr){
		
		int size = dataList.size();//数据条数
		int arrSize = dataList.get(0).length;//数组大小
		double[] powArr = new double[arrSize];//存储数据和，顺序和传入数据一致
		for(double[] data : dataList){
			
			for(int i = 0; i < data.length; i++){
				powArr[i] += Math.pow(data[i] - averageArr[i], 2);
			}
		}
		double[] deviationArr = new double[arrSize];//各标准差，顺序和传入数据一致
		for(int i = 0; i < arrSize; i++){
			
			deviationArr[i] = Math.sqrt(powArr[i]/size);
		}
		
		return deviationArr;
	}
	
	/**
	 * 正态分布/高斯分布
	 * @param data 随机变量x
	 * @param average 平均数μ
	 * @param deviation 标准差σ
	 * @return 概率
	 */
	public static double gaussianDistribution(double data, double average, double deviation){
		
		double result = (1/(Math.sqrt(2*Math.PI)*deviation))*Math.exp(-(Math.pow((data-average), 2))/(2*Math.pow(deviation, 2)));
		return result;
	}
	
	public static void main(String[] args) {
		
		double[] d = new double[2];
		d[0] = 2.6;
		d[1] = 3.8;
		List<double[]> list = new ArrayList<double[]>();
		list.add(d);double[] d2 = new double[2];
		d2[0] = 2.0;
		d2[1] = 3.0;
		list.add(d2);
		for(int i = 0; i < list.size(); i++){
			log.info(String.valueOf(list.get(i)[0]+":"+list.get(i)[1]));
		}
		log.info(String.valueOf(NaiveBayes.average(list)));
		double val = 2/1;
		log.info(String.valueOf(val));
	}
	
}
